/*
The MIT License (MIT)

Copyright (c) 2013 Mike Dapiran, Brian May, Richard Pospesel, and Bert Wierenga

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software 
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#pragma once

#include "hhdPhysics.h"

#include "hhdLighting.h"
#include "hhdRegistry.h"
#include "hhdGfxPlatform.h"

#include "hhdSmartPtr.hpp"
#include "hhdGfxMaterial.h"

namespace hhd
{
	class CCamera;
	class IProcess;
	class CSpotLight;
	class CDirectionalLight;
	class CPointLight;
	class CMeshRenderer;
	class ShadowMapGenerationProcess;
	class Texture;
	class GfxPass;

	/*
	* This class handles the rendering of all renderable components on a scene
	* by scene basis. This class holds an ordered list of classes that extend
	* IProcess. Each process is responsible for handling the rendering of a
	* specific class that extends IComponent.
	*
	* @see IProcess
	* @see Scene
	* @see Camera
	* @see Transform
	* @see DirectionalLight
	* @see PointLight
	* @see SpotLight
	* @see LightingInfo
	*
	* @auther Mike Dapiran
	* @author Bert Wierenga
	*/
	class GfxDirector : public IDirector, public IMessageReceiver
	{			
		DirectorH(hhd::GfxDirector, GfxDirector);
		HHD_REGISTRANT_H(IDirector, GfxDirector);

	public:			
		/*
		* Default constructor sets active camera to NULL.
		*/
		GfxDirector(void);
		~GfxDirector(void);

		/*
		* Called by the Scene we belong to. We will draw a single frame.
		*/
		void draw();

		/*
		* Called by the Scene we belong to so that we can do any updating 
		* necessary.
		*/
		void update(const GameTimer& in_gt);
			
		/*
		* Called by the Scene we belong to so that we can do any initializing
		* necessary.
		*/ 
		void initialize();

		/*
		* Called to load this Director from an XML block.
		*/
		IDirector* deserializeFromXML(const TiXmlElement* in_xml_element);
		
		/*
		* This function is called by any class that extends IComponent that is involved
		* in rendering so that it may be held onto appropriately.
		*
		* @param in_component An instance of a component that is involved in rendering.
		*/
		void registerComponent(hhd::IComponent* in_component);
			
		/*
		* Sets the active camera
		*
		* @param in_camera The Camera that is to become that main camera used for rendering.
		*/
		void setActiveCamera(CCamera* in_camera);		

		void unregisterComponent(IComponent* in_component);

	private:
		void deserializeRenderTargetFromXml(const TiXmlElement* in_xml_element);
		void deserializeRenderTargetSetFromXml(const TiXmlElement* in_xml_element);
		void deserializePassFromXml(const TiXmlElement* in_xml_element);
		void deserializeMaterialFromXml(const TiXmlElement* in_xml_element);

		static void handle_culling_message(IMessageReceiver*, IMessage*);

		/**
		* Called by fillOutLighting to determine and write the light data into a MeshRenderer's
		* LightingInfo structure.
		*
		* @param in_nonculled_components All components that have not been culled
		*/
		inline void binInFrustumPointLights( HashSet<void*>* in_nonculled_components );

		/**
		* Called by fillOutLighting to determine and write the light data into a MeshRenderer's
		* LightingInfo structure.
		*
		* @param in_mesh_renderer The MeshRenderer we want to determine the highest
		* priority DirectionalLight's for.
		*/
		inline void binInFrustumDirectionalLights( CCamera* in_camera );

		/**
		* Called by fillOutLighting to determine and write the light data into a MeshRenderer's
		* LightingInfo structure.
		*
		* @param in_nonculled_components All components that have not been culled
		*/
		inline void binInFrustumSpotLights(HashSet<void*>* in_nonculled_components );

		/**
		* MeshRenderer's that want lighting
		*/
		Vector<CMeshRenderer*> _lit_meshes;

		/**
		* MeshRenderer's that do not want lighting
		*/
		Vector<CMeshRenderer*> _emissive_meshes;

		/**
		* All the point lights in the Scene.
		*/
		Vector<CPointLight*> _point_lights;	

		/**
		* All the Spot lights in the Scene.
		*/
		Vector<CSpotLight*> _spot_lights;	

		/**
		* All the directional lights in the Scene.
		*/
		Vector<CDirectionalLight*> _directional_lights;

		//bins so memory allocation isn't happening over and over
		Vector<CPointLight*> _pl_bin;
		Vector<CDirectionalLight*> _dl_bin;
		Vector<CSpotLight*> _sl_bin;

		/** 
		* This is called at the beginning of each draw call to give
		* each component that wants lighting info the most pertinent
		* info
		*/
		inline void fillOutLighting(CCamera* in_camera, HashSet<void*>* in_nonculled_components);

		CCamera* _active_camera;
		CullingFrustum* _cull_frustrum; // shouldn't this just come from the camera?

				//This contains our components that our collided with last frame
		HashSet<IComponent*> _nonculled_components;

		/**
		* Used in coneCull.
		*/
		static const float far_clip_radius;

		HashTable<String, GfxRenderTarget*> _gfx_render_targets;
		HashTable<String, GfxRenderTargetSet*> _gfx_render_target_sets;
		Vector<GfxPass*> _gfx_passes;
		Vector< SmartPtr<GfxMaterial> > _gfx_materials;
	};
}

